﻿//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Query Application Block
//===============================================================================

using System;
using System.Data;
using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using EntLibContrib.Query.Configuration;
using EntLibContrib.Query.Parameters;
using EntLibContrib.Query.Commands;
using EntLibContrib.Query.Properties;

namespace EntLibContrib.Query.Queries
{
	/// <summary>
	/// Xml Query.
	/// </summary>
	/// <remarks>
	/// This provider creates a query for an Xml file.
	/// </remarks>
	[ConfigurationElementType(typeof(XmlFileQueryData))]
	public class XmlFileQuery : FileQuery
	{
		#region Fields
		private string element;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new default instance of the <see cref="XmlFileQuery"/> class.
		/// </summary>
		/// <param name="name">The query name.</param>
		/// <param name="element">The XML element that contains the object data.</param>
		/// <param name="dataFile">The XML data file.</param>
		/// <param name="customCommand">The custom command.</param>
		/// <param name="parameterSet">The parameter set.</param>
		///// <param name="instrumentationProvider">The instrumentation provider.</param>
		public XmlFileQuery(string name,
												string element,
												string dataFile,
												ICommand customCommand, 
												IParameterSet parameterSet)
												//, QueryInstrumentationProvider instrumentationProvider)
			: base(name, dataFile, customCommand, parameterSet) //, instrumentationProvider)
		{
			ValidateAndStoreParameters(element);
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Executes a read command and returns the results.
		/// </summary>
		/// <param name="parameterValues">The parameter values.</param>
		/// <returns>
		/// Dataset containing the results of the read operation
		/// </returns>
		/// <remarks>
		/// 	<para>This method takes the parameter values from the given dictionary.</para>
		/// 	<para>Output parameters will update the parameter property values.</para>
		/// </remarks>
		public override DataSet ExecuteForRead(IDictionary<string, object> parameterValues)
		{
			try
			{
				// set the parameter values given in the dictionary
				if (parameterValues != null)
					SetParameterValues(parameterValues);

				// invoke the service method which must return a DataSet
				DataSet results = BuildCommand().ExecuteForRead();

				// update the instrumentation counters
				UpdateReadCounters(results);

				// return the results
				return results;
			}
			catch (Exception exception)
			{
				// log and rethrow the error
				LogReadError(exception);
				throw;
			}
		}

		/// <summary>
		/// Executes a write command and saves data to the data source.
		/// </summary>
		/// <param name="parameterValues">The parameter values.</param>
		/// <remarks>
		/// 	<para>This method takes the parameter values from the given dictionary.</para>
		/// 	<para>Output parameters will update the parameter property values.</para>
		/// </remarks>
		public override void ExecuteForWrite(IDictionary<string, object> parameterValues)
		{
			try
			{
				// set the parameter values given in the dictionary
				if (parameterValues != null)
					SetParameterValues(parameterValues);

				// invoke the service method which must return void
				BuildCommand().ExecuteForWrite();

				// update the instrumentation counters
				UpdateWriteCounters();
			}
			catch (Exception exception)
			{
				// log and rethrow the error
				LogWriteError(exception);
				throw;
			}
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Validates the and store parameters.
		/// </summary>
		/// <param name="elementName">Name of the element.</param>
		private void ValidateAndStoreParameters(string elementName)
		{
			// check for a null or empty element
			if (string.IsNullOrEmpty(elementName))
				throw new ArgumentNullException("elementName", InternalResources.ExceptionXmlFileQueryElementNullOrEmpty);
			// store the element
			this.element = elementName;
		}

		/// <summary>
		/// Builds the command for the specified database to use.
		/// </summary>
		/// <returns>The built command</returns>
		/// <remarks>The parameter dictionary can contain any parameter type
		/// unless you need a namespace in which you must use <see cref="XmlParameter"/> types</remarks>
		protected override ICommand BuildCommand()
		{
			// check for a custom command
			if (CustomCommand == null)
				return new XmlFileCommand(element, DataFile, ParameterSet.Parameters);
			else
			{
				Commands.FileCommand customFileCommand = (Commands.FileCommand)(CustomCommand);

                if (!string.IsNullOrEmpty(DataFile)) customFileCommand.DataFile = DataFile;
                if (ParameterSet.Parameters.Count > 0) customFileCommand.AddParameters(ParameterSet.Parameters);

                return customFileCommand;
			}
		}
		#endregion
	}
}
